package internal

import (
	"errors"
	"go/token"
)

var (
	ErrInvalidValue = errors.New("invalid value")
	ErrHaveReturn   = errors.New("have return values")
	ErrNoFiles      = errors.New("no files to derive output directory from")
)

// errorCollector manages a list of errors. The zero value is an empty list.
type errorCollector struct {
	errors []error
}

// add appends any non-nil errors to the collector.
func (ec *errorCollector) add(errs ...error) {
	for _, err := range errs {
		if err != nil {
			ec.errors = append(ec.errors, err)
		}
	}
}

// A bindError is an error with an optional position.
type bindError struct {
	error    error
	position token.Position
}

// notePosition wraps an error with position information if it doesn't already
// have it.
//
// notePosition is usually called multiple times as an error goes up the call
// stack, so calling notePosition on an existing *wireErr will not modify the
// position, as the assumption is that deeper calls have more precise position
// information about the source of the error.
func notePosition(pos token.Position, err error) error {
	if err == nil {
		return nil
	}

	var myErr *bindError

	if errors.As(err, &myErr) {
		return err
	}

	return &bindError{error: err, position: pos}
}

// Error returns the error message prefixed by the position if valid.
func (w *bindError) Error() string {
	if !w.position.IsValid() {
		return w.error.Error()
	}

	return w.position.String() + ": " + w.error.Error()
}
